﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using Ivi.Driver.Interop;
using System.Globalization;

namespace AIRO.Devices.DCPwr
{ 
    [Guid("2734B1BA-487A-11DD-B5DB-334556D89593")]
    [ClassInterface(ClassInterfaceType.None)]
    [ProgId("MyDevices.DCPwr.Yokogawa7651")]
    public class Yokogawa7651 : BasicIviDriverVisa, Ivi.DCPwr.Interop.IIviDCPwr, Ivi.Driver.Interop.IIviDriver, IIviDriverIdentity, IIviComponentIdentity, IIviDriverOperation, IIviDriverUtility 
    {
        //bool isHeaderOn;
        private struct OutputData
        {
            public bool IsOverloaded;
            public string ACDC;
            public string Units;
            public double Data;
        }
        private Ivi.DCPwr.Interop.IIviDCPwrOutputs _outputs;
        

        public Yokogawa7651()
        {
            _description = "IVI Custom Driver for Yokogawa 7651";
            _identifier = "Yokogawa 7651";
            _instrumentManufacturer = "Yokogawa";
            _supportedInstrumentModels = "Yokogawa7651";
            _vendor = "Abteilung v. Klitzing, FKF-MPI";
            _outputs = new Y7651Outputs(this);
        }

        private bool ParseOutputData(string outputData, out OutputData res)
        {
            string outputDataPattern;
            res = new OutputData();
            Match m;
            Regex outputDataRegex;            
            outputDataPattern = @"((?<A1>[NE])(?<A2A3>DC)(?<A4>[VA]))?(?<Data>[+-]?\d*\.?\d*E[+-]?\d)";                       
            outputDataRegex = new Regex(outputDataPattern, RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase | RegexOptions.Singleline);
            m=outputDataRegex.Match(outputData);            
            if (m.Success)
            {
                if (m.Groups["A1"].Value == "N")
                    res.IsOverloaded = false;
                else
                    res.IsOverloaded = true;
                res.ACDC = m.Groups["A2A3"].Value;
                res.Units = m.Groups["A4"].Value;
                res.Data = System.Convert.ToDouble(m.Groups["Data"].Value, numericFormatProvider);                
                return true;
            }
            else
            {
                return false;
            }
        }

        public void Disable()
        {

        }


        #region IIviDCPwr Members


        public void Initialize(string ResourceName, bool IdQuery, bool Reset, string OptionString)
        {
            if (!_initialized)
            {
                _rangeCheck = true;
                _cache = true;
                _queryInstrumentStatus = false;
                _simulate = false;
                _driverSetup = "";
                _recordCoercions = false;
                _interchangeCheck = false;
                

                InitVisaMessageBasedSession(ResourceName);
                instrument.IO.Timeout = 5000;
                instrument.IO.TerminationCharacter = 13;
                instrument.IO.TerminationCharacterEnabled = true;
                ParseOptionString(OptionString);
                if (Reset)
                {
                    this.Reset();
                }
                string cmd = "DL2\r\n";
                string res= Query(cmd);
                
                _initialized = true;
                
            }
            else
            {
                iviDriverErrorQueue.Enqueue(new Error(IviDriver_ErrorCodes.E_IVI_ALREADY_INITIALIZED));
            }
        }

        public Ivi.DCPwr.Interop.IIviDCPwrOutputs Outputs
        {
            get { return _outputs; }
        }

        public Ivi.DCPwr.Interop.IIviDCPwrTrigger Trigger
        {
            get { throw new NotImplementedException(); }
        }

        #endregion

        private class Output : Ivi.DCPwr.Interop.IIviDCPwrOutput, ICurrentSource
        {
            protected NumberFormatInfo numericFormatProvider = new NumberFormatInfo();
            Yokogawa7651 driver;

            public Output()
            {
                numericFormatProvider.PercentDecimalSeparator = ".";
                numericFormatProvider.CurrencyDecimalSeparator = ".";
                numericFormatProvider.NumberDecimalSeparator = ".";
            }

            public Output(Yokogawa7651 Driver):this()
            {
                this.driver = Driver;
            }

            #region IIviDCPwrOutput Members

            public void ConfigureCurrentLimit(Ivi.DCPwr.Interop.IviDCPwrCurrentLimitBehaviorEnum Behavior, double Limit)
            {
                throw new NotImplementedException();
            }

            public void ConfigureOVP(bool Enabled, double Limit)
            {
                throw new NotImplementedException();
            }

            public void ConfigureRange(Ivi.DCPwr.Interop.IviDCPwrRangeTypeEnum RangeType, double Range)
            {
                string cmd;
                if (RangeType == Ivi.DCPwr.Interop.IviDCPwrRangeTypeEnum.IviDCPwrRangeCurrent)
                {
                    cmd = "F5/";
                    if (Math.Abs(Range) <= 0.001)
                        cmd += "R4\r\n";
                    else if (Math.Abs(Range) <= 0.01)
                        cmd += "R5\r\n";
                    else if (Math.Abs(Range) <= 0.1)
                        cmd += "R6\r\n";
                }
                else
                {
                    cmd = "F1/";
                    if (Math.Abs(Range) <= 0.01)
                        cmd += "R2\r\n";
                    else if (Math.Abs(Range) <= 0.1)
                        cmd += "R3\r\n";
                    else if (Math.Abs(Range) <= 1)
                        cmd += "R4\r\n";
                    else if (Math.Abs(Range) <= 10)
                        cmd += "R5\r\n";
                    else if (Math.Abs(Range) <= 30)
                        cmd += "R6\r\n";
                }
                string res = driver.Query(cmd);
            }

            public double CurrentLimit
            {
                get
                {
                    throw new NotImplementedException();
                }
                set
                {
                    if ((value >= 0.005) & (value <= 0.120))
                    {
                        string cmd = String.Format(numericFormatProvider, "LA{0}\r\n", value * 1000);
                        string res = driver.Query(cmd);
                    }
                    else
                    {
                        throw new ArgumentException("The units are Amps. The current limit can be set in the range 0.005 to 0.120 A");
                    }
                }
            }

            public Ivi.DCPwr.Interop.IviDCPwrCurrentLimitBehaviorEnum CurrentLimitBehavior
            {
                get
                {
                    throw new NotImplementedException();
                }
                set
                {
                    throw new NotImplementedException();
                }
            }

            public bool Enabled
            {
                get
                {
                    throw new NotImplementedException();
                }
                set
                {
                    string cmd;
                    if (value)
                        cmd = "O1\r\n";
                    else
                        cmd = "O0\r\n";                    
                    string res = driver.Query(cmd);
                    cmd = "E\r\n";
                    driver.Query(cmd);
                }
            }

            public double Measure(Ivi.DCPwr.Interop.IviDCPwrMeasurementTypeEnum MeasurementType)
            {
                throw new NotImplementedException();
            }

            public bool OVPEnabled
            {
                get
                {
                    throw new NotImplementedException();
                }
                set
                {
                    throw new NotImplementedException();
                }
            }

            public double OVPLimit
            {
                get
                {
                    throw new NotImplementedException();
                }
                set
                {
                    if ((value <= 30)&(value>=1))
                    {
                        string cmd = String.Format(numericFormatProvider, "LV{0}\r\n", value);
                        string res = driver.Query(cmd);
                    }
                    else
                        throw new ArgumentException("Voltage limite can be set in the range 1 to 30 V");
                }
            }

            public double QueryCurrentLimitMax(double VoltageLevel)
            {
                throw new NotImplementedException();
            }

            public bool QueryState(Ivi.DCPwr.Interop.IviDCPwrOutputStateEnum OutputState)
            {                
                throw new NotImplementedException();
            }

            public double QueryVoltageLevelMax(double CurrentLimit)
            {
                throw new NotImplementedException();
            }

            public void ResetOutputProtection()
            {
                throw new NotImplementedException();
            }

            public Ivi.DCPwr.Interop.IviDCPwrTriggerSourceEnum TriggerSource
            {
                get
                {
                    throw new NotImplementedException();
                }
                set
                {
                    throw new NotImplementedException();
                }
            }

            public double TriggeredCurrentLimit
            {
                get
                {
                    throw new NotImplementedException();
                }
                set
                {
                    throw new NotImplementedException();
                }
            }

            public double TriggeredVoltageLevel
            {
                get
                {
                    throw new NotImplementedException();
                }
                set
                {
                    throw new NotImplementedException();
                }
            }

            public double VoltageLevel
            {
                get
                {
                    throw new NotImplementedException();
                }
                set
                {
                    string cmd = "F1\r\n";
                    string res = driver.Query(cmd);
                    cmd= String.Format(numericFormatProvider, "S{0}", value);                     
                    res = driver.Query(cmd);
                    cmd = "E\r\n";
                    res=driver.Query(cmd);
                }
            }

            public double CurrentLevel
            {
                get
                {
                    throw new NotImplementedException();
                }
                set
                {
                    string cmd = "F5\r\n";
                    string res = driver.Query(cmd);
                    cmd = String.Format(numericFormatProvider, "S{0}", value);
                    res = driver.Query(cmd);
                    cmd = "E\r\n";
                    res = driver.Query(cmd);
                }
            }

            #endregion
        }

        private class Y7651Outputs : Ivi.DCPwr.Interop.IIviDCPwrOutputs
        {
            private Output[] outputsArray;

            public Y7651Outputs(Yokogawa7651 Driver)
            {
                outputsArray = new Output[]{new Output(Driver)};
                
            }

            #region IIviDCPwrOutputs Members

            public int Count
            {
                get { return outputsArray.Length; }
            }

            public Ivi.DCPwr.Interop.IIviDCPwrOutput get_Item(string OutputName)
            {
                int i;
                Output res;
                try
                {
                    i=System.Convert.ToInt32(OutputName);
                    res = outputsArray[i];
                }
                catch
                {
                    throw new ArgumentException("No such output!");
                }
                return res;
            }

            public string get_Name(int Index)
            {
                return System.Convert.ToString(Index);
            }

            #endregion
        }

    }
}
